package gsw.tool.pluggable.hook.handler;

import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.os.Handler;
import android.os.Message;

import java.lang.reflect.Field;

import gsw.tool.pluggable.core.Env;
import gsw.tool.pluggable.core.PluginManager;

/**
 * Hook系统的ActivityThread的mH的Callback，用来修改luanchActiity消息的回调。
 * 开启新进程打开插件时，即时修改了applicationInfo.packageName，系统也会从宿主APK中查找组件，这样就会导致找不到插件的组件而崩溃。
 * 为了避免崩溃，设定第一次进行Hook时，即新建进程打开插件时，直接打开代理组件。
 */
public class HandlerMH implements Handler.Callback {
    //系统的ActivityThread的mH
    private Handler mH;
    //拦截次数
    int times = 1;

    public HandlerMH(Handler mH) {
        this.mH = mH;
    }

    @Override
    public boolean handleMessage(Message msg) {
        //msg.what==100，代表加载activity
        if (msg.what == 100) {
            //跳转插件Activity
            handleLuachActivity(msg);
        }
        //调用系统的handleMessage(),执行luanchActivity
        mH.handleMessage(msg);
        return true;
    }

    /**
     * 跳转插件Activity
     *
     * @param msg
     */
    private void handleLuachActivity(Message msg) {
        Object obj = msg.obj;
        try {
            Field intentField = obj.getClass().getDeclaredField("intent");
            intentField.setAccessible(true);
            //代理意图
            Intent proxyIntent = (Intent) intentField.get(obj);
            //真实意图
            Intent oldIntent = proxyIntent.getParcelableExtra(Env.EXTRA_TARGET_INTENT);

            //如果是第一次拦截，就退出
            if (times++ <= 1) {
                return;
            }

            //开启代理组件的进程时，初始自定义AMS中的代理进程的信息
            onOpenPluginProcess(proxyIntent, oldIntent);

            if (oldIntent != null) {
                //还原真实的意图
                proxyIntent.setComponent(oldIntent.getComponent());
                /**
                 * 获取activityInfo对象
                 */
                Field activityInfoField = obj.getClass().getDeclaredField("activityInfo");
                activityInfoField.setAccessible(true);
                ActivityInfo activityInfo = (ActivityInfo) activityInfoField.get(obj);
                /**
                 * 修改activityInfo的包名。如果是宿主的Activity，则不需要修改包名；如果是插件的Activity，就需要修改为插件的包名。
                 * 因为使用loadedApk插入的方式加载插件的类时，会生成新的loadedApk对象，这个时候就需要根据插件的包名，从ActivityThrea中查找插件的loadedApk对象。
                 */
                activityInfo.applicationInfo.packageName = proxyIntent.getComponent().getPackageName();

                //加载插件APK的loadedAPK。因为插件APK没有安装到系统中，是由自定义的PMS管理的，所以需要通把插件APK的loadedAPK对象插入到宿主中，即把插件的类插入到宿主中。
                PluginManager.preLoadApk(oldIntent.getComponent());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 开启代理组件的进程时，初始自定义AMS中的代理进程的信息
     *
     * @param proxyIntent 代理意图
     * @param oldIntent   插件意图
     */
    private void onOpenPluginProcess(Intent proxyIntent, Intent oldIntent) {
        //获取代理组件的存档信息
        ResolveInfo resolveInfo = PluginManager.getContext().getPackageManager().resolveActivity(proxyIntent, 0);
        ActivityInfo stubActivityInfo = resolveInfo != null ? resolveInfo.activityInfo : null;
        //获取插件组件的存档信息
        ActivityInfo targetInfo = PluginManager.getInstance().getActivityInfo(oldIntent.getComponent(), 0);
        if (targetInfo != null) {
            PluginManager.getInstance().onOpenPluginProcess(stubActivityInfo.processName, targetInfo.processName, targetInfo.packageName);
        }
    }
}
